﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Entities;
using RepositoriesInterfaces;
using Subfaculty.ViewModels;
using System.Text;
using Subfaculty.ViewModels.Binders;

namespace Subfaculty.Controllers
{
    public class AllocationController : Controller
    {
        public IStudyPlanItemRepository PlanItemRepository;
        public IGroupRepository GroupRepository;
        IAllocationRepository AllocationRepository;
        IDirectionRepository DirectionRepository;
        IDisciplineRepository DisciplineRepository;
        IDepartmentRepository DepartmentRepository;        
        ILoadAtomRepository LoadAtomRepository;

        public AllocationController(IStudyPlanItemRepository PlanItemRepository, IAllocationRepository AllocationRepository, 
                                    IDirectionRepository DirectionRepository, IDisciplineRepository DisciplineRepository,
                                    IDepartmentRepository DepartmentRepository, IGroupRepository GroupRepository, ILoadAtomRepository LoadAtomRepository)
        {
            this.AllocationRepository = AllocationRepository;
            this.DirectionRepository = DirectionRepository;
            this.DisciplineRepository = DisciplineRepository;
            this.DepartmentRepository = DepartmentRepository;
            this.PlanItemRepository = PlanItemRepository;
            this.GroupRepository = GroupRepository;
            this.LoadAtomRepository = LoadAtomRepository;
        }

        public ActionResult Index(int id)
        {
            int currentDepartmentId = GetCurrentDepartmentId(id);
            var model = new AllocationListViewModel
            {
                Allocations = AllocationRepository.GetByDepartmentId(currentDepartmentId),
                curentDepartment = currentDepartmentId
            };

            ViewData["curentDepartment"] = GetDepartmentsList(currentDepartmentId);
            return View(model);
        }

        [HttpGet]
        public ActionResult Create(int id)
        {
            int currentDirectionId = GetCurrentDirectionId(id);
            var model = new AllocationCreateViewModel
            {
                StudyPlanItems = PlanItemRepository.GetByDirectionId(currentDirectionId),
                curentDirection = currentDirectionId,
                FactorForConsultation = 0.05,
                FactorForControl = 0.3,
                RatingFactor = 0.0015,
                FactorForBeforeExamConsultation = 2
            };
            ViewData["curentDirection"] = GetDirectionList(currentDirectionId);
            
            return View(model);
        }

        [HttpPost]
        public ActionResult Create([ModelBinder(typeof(AllocationCreateBinder))] AllocationCreateViewModel model)
        {
            Allocation newAllocation = new Allocation(); 
            CreateNewAllocation(newAllocation, model);

            if (newAllocation.StudyPlanItems.First().HoursLecture != 0)
                CreateLoadAtoms("Лекции", "allGroups", newAllocation, model.Groups);
            if (newAllocation.StudyPlanItems.First().HoursPractice != 0)
                CreateLoadAtoms("Практики", model.typePracticeSplitting, newAllocation, model.Groups);
            if (newAllocation.StudyPlanItems.First().HoursLaboratory != 0)
                CreateLoadAtoms("Лабораторные", model.typeLabSplitting, newAllocation, model.Groups);
            AllocationRepository.SaveOrUpdate(newAllocation);

            return Redirect(Url.Action("Index"));
        }

        [HttpGet]
        public ActionResult Delete(int id)
        {
            Allocation allocation = AllocationRepository.GetByID(id);
            IList<StudyPlanItem> SPIList = allocation.StudyPlanItems;
            IEnumerator<StudyPlanItem> enumeratorList = SPIList.GetEnumerator(); enumeratorList.MoveNext();
            StudyPlanItem SPItem = enumeratorList.Current;
            int departmentId = SPItem.Department.Id;
            AllocationRepository.Delete(allocation);

            return RedirectToAction(String.Format("Index/{0}", departmentId));
        }
                
        // --------------AJAX FUNCTIONS--------------

        public PartialViewResult ajaxGetSPIListByDirection(int id)
        {
            IList<StudyPlanItem> SPILIst = PlanItemRepository.GetByDirectionId(id);
            AjaxUpdateSPIListViewModel model = new AjaxUpdateSPIListViewModel { StudyPlanItemList = SPILIst };

            return PartialView(model);
        }

        public PartialViewResult ajaxGetSameSPIList(int id)
        {
            IList<StudyPlanItem> SPILIst = PlanItemRepository.GetSameSPIItem(id);     
            
            AjaxUpdateSPIListViewModel model = new AjaxUpdateSPIListViewModel { StudyPlanItemList = SPILIst };

            return PartialView(model); 
        }

        public String ajaxUpdateSPItem(int id)
        {
            StudyPlanItem SPItem = PlanItemRepository.GetByID(id);
            StringBuilder str = new StringBuilder();
            str.Append(String.Format("<input id='StudyPlanItem' type='text' readonly='readonly' value='{0}' size='140' />", SPItem.Discipline.DisciplineTitle + "  (Направление : " + SPItem.Direction.DirectionTitle + ")"));
            str.Append(String.Format("<input id='SPIhidden' type='hidden' name='spi_{0}' value='{0}' />", SPItem.Id));

            return str.ToString();
        }

        // id - список id выбранных учебных планов
        public PartialViewResult ajaxUpdateGroupList(String id)
        {
            IList<String> idArray = id.Split('_');
            IList<StudyPlanItem> SPItemList = new List<StudyPlanItem>();
            
            foreach (String item in idArray)            
                SPItemList.Add(PlanItemRepository.GetByID(Convert.ToInt32(item)));

            IList<Group> GroupsList = GroupRepository.GetBySPItemsList(SPItemList);
            StringBuilder str = new StringBuilder();
            AjaxUpdateGroupListViewModel model = new AjaxUpdateGroupListViewModel { GroupsList = GroupsList };

            return PartialView(model);
        }
        

        // --------------PRIVATE FUNCTIONS--------------

        // Генерирует атомы нагрузки
        private void CreateLoadAtoms(String LoadType, String typeSplitting, Allocation allocation, IList<Group> groups)
        {
            if (typeSplitting == "oneGroup")
                GenerateLoadAtomToEachGroup(allocation, LoadType, groups);
            else if (typeSplitting == "allGroups")
                GenerateLoadAtomToAllGroup(allocation, LoadType, groups);
            else if (typeSplitting == "halfGroup")
                GenerateLoadAtomToHalfGroup(allocation, LoadType, groups);
        }

        // Сгенерировать атом для всех подгрупп
        private void GenerateLoadAtomToHalfGroup(Allocation allocation, string LoadType, IList<Group> groups)
        {
            LoadAtom atom;
            IList<Group> tempGroupList = new List<Group>();

            foreach (Group item in groups)
            {
                tempGroupList.Clear();
                tempGroupList.Add(item);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "halfGroup" + "_1");
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "halfGroup" + "_2");
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
            }
        }

        // Сгенерировать атом для всех групп из списка
        private void GenerateLoadAtomToAllGroup(Allocation allocation, String LoadType, IList<Group> groups)
        {
            LoadAtom atom = CreateNewAtom(LoadType, groups, allocation, "allGroups");
            LoadAtomRepository.SaveOrUpdate(atom);
            allocation.LoadAtoms.Add(atom);
        }

        // Сгенерировать атомы для каждой группы из списка в отдельности
        private void GenerateLoadAtomToEachGroup(Allocation allocation, String LoadType, IList<Group> groups)
        {
            LoadAtom atom;
            IList<Group> tempGroupList = new List<Group>();

            foreach (Group item in groups)
            {
                tempGroupList.Clear();
                tempGroupList.Add(item);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "oneGroup");
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
            }
        }

        private void CreateNewAllocation(Allocation newAllocation, AllocationCreateViewModel model)
        {
            newAllocation.FactorForBeforeExam = (float)model.FactorForBeforeExamConsultation;
            newAllocation.RatingFactor = (float)model.RatingFactor;
            newAllocation.FactorForConsultation = (float)model.FactorForConsultation;
            newAllocation.FactorForControl = (float)model.FactorForControl;
            foreach (StudyPlanItem item in model.StudyPlanItems)
                newAllocation.AddStudyPlanItem(item);
            AllocationRepository.Save(newAllocation);
        }

        private LoadAtom CreateNewAtom(String loadType, IList<Group> groups, Allocation allocation, String GroupRelationType)
        {
            LoadAtom atom = new LoadAtom();

            atom.LoadType = loadType;
            atom.Teacher = null;
            atom.Allocation = allocation;
            atom.GroupRelationType = GroupRelationType;

            IEnumerator<StudyPlanItem> enumerator = allocation.StudyPlanItems.GetEnumerator();
            enumerator.Reset(); enumerator.MoveNext();
            if (loadType == "Лекции")
                atom.Hours = enumerator.Current.HoursLecture;
            else if (loadType == "Практики")
                atom.Hours = enumerator.Current.HoursPractice;
            else if (loadType == "Лабораторные")
                atom.Hours = enumerator.Current.HoursLaboratory;
            LoadAtomRepository.Save(atom);
            foreach (Group item in groups)
                item.AddAtom(atom);

            return atom;
        }

        private int GetCurrentDepartmentId(int id)
        {
            IList<Department> DepartmentsList = DepartmentRepository.GetAll();
            int curId = id;
            if ((id == 0) && (DepartmentsList.Count != 0))
            {
                curId = DepartmentsList[0].Id;
            }
            return curId;
        }

        private int GetCurrentDirectionId(int id)
        {
            IList<Direction> DirectionsList = DirectionRepository.GetAll();
            int curId = id;
            if ((id == 0) && (DirectionsList.Count != 0))
            {
                curId = DirectionsList[0].Id;
            }
            return curId;
        }

        private IEnumerable<SelectListItem> GetDirectionList(int idSelectedDirection)
        {
            return DirectionRepository.GetAll()
                                .Select(direction => new SelectListItem
                                {
                                    Selected = (direction.Id == idSelectedDirection),
                                    Text = direction.DirectionTitle,
                                    Value = direction.Id.ToString()
                                });
        }

        private IEnumerable<SelectListItem> GetDepartmentsList(int idSelectedDepartment)
        {
            return DepartmentRepository.GetAll()
                                .Select(department => new SelectListItem
                                {
                                    Selected = (department.Id == idSelectedDepartment),
                                    Text = department.DepartmentTitle,
                                    Value = department.Id.ToString()
                                });
        }
    }
}
